﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WaveEngine.Common.Math;
using WaveEngine.Extensions.ITasks;
using WaveEngine.Framework;
using WaveEngine.Framework.Animation;
using WaveEngine.Framework.Graphics;

namespace WaveEngine.Extensions.Behaviors
{
    public class ShakeBehavior : Behavior
    {
        [RequiredComponent]
        private Transform2D transform;

        private Transform2D parentTransform;

        private Vector2 originPosition;

        public TimeSpan Duration { get; set; }

        private TimeSpan shakeMaxTime;
        private TimeSpan shakeTimer;
        private TimeSpan totalTimer;

        public float XOscilation { get; set; }

        public float YOscilation { get; set; }

        public IEasingFunction EasingFunction { get; set; }

        public ShakeBehavior(float duration = 0.5f, int numberOfShakes = 5, float xOscilation = 20, float yOscilation = 0)
        {
            this.Duration = TimeSpan.FromSeconds(duration);
            this.shakeMaxTime = TimeSpan.FromSeconds(duration / numberOfShakes);
            this.shakeTimer = TimeSpan.Zero;
            this.XOscilation = xOscilation;
            this.YOscilation = yOscilation;
            this.IsActive = false;
        }

        protected override void Update(TimeSpan gameTime)
        {
            if (this.totalTimer > this.Duration)
            {
                this.Reset();
                return;
            }
            else if (this.shakeTimer > this.shakeMaxTime)
            {
                this.shakeTimer = TimeSpan.Zero;
            }

            double elapsed = this.shakeTimer.TotalSeconds / this.shakeMaxTime.TotalSeconds;
            if (EasingFunction != null)
            {
                elapsed = EasingFunction.Ease(elapsed);
            }

            transform.X = originPosition.X + (float)(Math.Sin(elapsed * Math.PI) * XOscilation);
            transform.Y = originPosition.Y + (float)(Math.Sin(elapsed * Math.PI) * YOscilation);

            //transform.X += (float)(Math.Sin(elapsed * Math.PI) * XOscilation);
            //transform.Y += (float)(Math.Sin(elapsed * Math.PI) * YOscilation);

            this.shakeTimer += gameTime;
            this.totalTimer += gameTime;
        }

        protected override void ResolveDependencies()
        {
            base.ResolveDependencies();
            if (this.Owner.Parent != null)
            {
                this.parentTransform = this.Owner.Parent.FindComponent<Transform2D>();
            }
            else
            {
                this.parentTransform = new Transform2D();
            }
            
            this.originPosition = new Vector2(this.transform.X - this.parentTransform.X, this.transform.Y - this.parentTransform.Y);
        }

        public void Reset()
        {
            this.shakeTimer = TimeSpan.Zero;
            this.totalTimer = TimeSpan.Zero;
            this.IsActive = false;            
            //this.transform.X = originPosition.X;
            //this.transform.Y = originPosition.Y;            
            this.originPosition = new Vector2(this.transform.X - this.parentTransform.X, this.transform.Y - this.parentTransform.Y);
        }

        public ITask CreateShakeTask()
        {
            return this.Owner.Scene.CreateActionTask(() =>
                    {
                        this.Reset();
                        this.IsActive = true;
                    }).AndWaitConditionActively(() => !this.IsActive);
        }

    }
}
